﻿using System;
using System.Collections.Generic;
using Heaven.Geometry;
using Microsoft.Xna.Framework.Graphics;

namespace Heaven.Xna.Graphics
{
    /// <summary>
    /// Caches device representaions of polygonal objects
    /// </summary>
    class PolygonalManager
    {
        #region Fields

        // Cache entity
        Dictionary<long, VisualGeometry> cache = new Dictionary<long, VisualGeometry>();

        #endregion

        #region Properties

        /// <summary>
        /// Count of meshes
        /// </summary>
        public int Count
        {
            get { return cache.Count; }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Constructor
        /// </summary>
        public PolygonalManager() { }

        #endregion

        #region Methods

        /// <summary>
        /// Draws the given polygonal object
        /// </summary>
        /// <param name="device">Graphics device</param>
        /// <param name="polygonal">Polygonal object</param>
        public void Draw(GraphicsDevice device, Polygonal polygonal)
        {
            VisualGeometry geometry = null;

            lock (cache)
            {
                if (!cache.TryGetValue(polygonal.Hash, out geometry))
                {
                    // Create visual geometry
                    geometry = new VisualGeometry(device, polygonal);
                    // Put into cache
                    cache.Add(polygonal.Hash, geometry);
                    // Subscibe event of changing mesh to remove it from cache
                    polygonal.Changed += new EventHandler(OnPolygonalChanged);
                    // And when object will be collected by GC
                    polygonal.GarbageCollected += new EventHandler(OnPolygonalGarbageCollected);
                }
            }
            // Render mesh
            geometry.Draw();
        }

        void OnPolygonalGarbageCollected(object sender, EventArgs e)
        {
            lock (cache)
            {
                long hash = ((Polygonal)sender).Hash;
                VisualGeometry visualGeometry = null;
                if (cache.TryGetValue(hash, out visualGeometry))
                {
                    visualGeometry.Dispose();
                    // Remove visual geometry from 
                    // cache, so it is not valid now
                    cache.Remove(hash);
                }
            }
        }

        void OnPolygonalChanged(object sender, EventArgs e)
        {
            lock (cache)
            {
                long hash = ((Polygonal)sender).Hash;
                VisualGeometry visualGeometry = null;
                if (cache.TryGetValue(hash, out visualGeometry))
                {
                    visualGeometry.Dispose();
                    // Remove visual geometry from 
                    // cache, so it is not valid now
                    cache.Remove(hash);
                }
            }
        }

        #endregion
    }
}
